// JWT 认证和密码哈希

use anyhow::Result;
use argon2::{
    password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
    Argon2,
};
use chrono::{Duration, Utc};
use common::UserRole;
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum AuthError {
    #[error("Password hashing failed")]
    PasswordHashError,
    #[error("Password verification failed")]
    PasswordVerifyError,
}

/// JWT Claims
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String,      // 用户ID
    pub role: UserRole,   // 用户角色
    pub exp: i64,         // 过期时间
    pub iat: i64,         // 签发时间
}

/// 生成 JWT Token
pub fn generate_token(user_id: &str, role: UserRole, secret: &str, expiry_hours: i64) -> Result<String> {
    let now = Utc::now();
    let exp = now + Duration::hours(expiry_hours);

    let claims = Claims {
        sub: user_id.to_string(),
        role,
        exp: exp.timestamp(),
        iat: now.timestamp(),
    };

    let token = encode(
        &Header::default(),
        &claims,
        &EncodingKey::from_secret(secret.as_bytes()),
    )?;

    Ok(token)
}

/// 验证 JWT Token
pub fn verify_token(token: &str, secret: &str) -> Result<Claims> {
    let token_data = decode::<Claims>(
        token,
        &DecodingKey::from_secret(secret.as_bytes()),
        &Validation::new(Algorithm::HS256),
    )?;

    Ok(token_data.claims)
}

/// 哈希密码
pub fn hash_password(password: &str) -> Result<String> {
    let salt = SaltString::generate(&mut rand::thread_rng());
    let argon2 = Argon2::default();
    let password_hash = argon2
        .hash_password(password.as_bytes(), &salt)
        .map_err(|_| AuthError::PasswordHashError)?
        .to_string();
    Ok(password_hash)
}

/// 验证密码
pub fn verify_password(password: &str, hash: &str) -> Result<bool> {
    let parsed_hash = PasswordHash::new(hash)
        .map_err(|_| AuthError::PasswordVerifyError)?;
    Ok(Argon2::default()
        .verify_password(password.as_bytes(), &parsed_hash)
        .is_ok())
}

// ========== RBAC 中间件 ==========

use axum::{
    extract::FromRequestParts,
    http::{StatusCode, header::AUTHORIZATION},
    Json,
};
use axum::http::request::Parts;
use async_trait::async_trait;

/// 认证用户信息（从 JWT 中提取）
#[derive(Debug, Clone)]
pub struct AuthUser {
    pub user_id: String,
    pub role: UserRole,
}

#[async_trait]
impl<S> FromRequestParts<S> for AuthUser
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, Json<serde_json::Value>);

    async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
        // 提取 Authorization header
        let auth_header = parts
            .headers
            .get(AUTHORIZATION)
            .and_then(|v| v.to_str().ok())
            .ok_or_else(|| {
                (
                    StatusCode::UNAUTHORIZED,
                    Json(serde_json::json!({
                        "code": 401,
                        "message": "Missing authorization header"
                    })),
                )
            })?;

        // 检查 Bearer token 格式
        let token = auth_header
            .strip_prefix("Bearer ")
            .ok_or_else(|| {
                (
                    StatusCode::UNAUTHORIZED,
                    Json(serde_json::json!({
                        "code": 401,
                        "message": "Invalid authorization format, expected: Bearer <token>"
                    })),
                )
            })?;

        // 从环境变量获取 JWT 密钥
        let secret = std::env::var("JWT_SECRET").unwrap_or_else(|_| "default_secret_change_me".to_string());

        // 验证 JWT
        let claims = verify_token(token, &secret).map_err(|_| {
            (
                StatusCode::UNAUTHORIZED,
                Json(serde_json::json!({
                    "code": 401,
                    "message": "Invalid or expired token"
                })),
            )
        })?;

        Ok(AuthUser {
            user_id: claims.sub,
            role: claims.role,
        })
    }
}

/// 检查用户是否拥有指定角色
pub fn require_role(user: &AuthUser, allowed_roles: &[UserRole]) -> Result<()> {
    if allowed_roles.contains(&user.role) {
        Ok(())
    } else {
        Err(anyhow::anyhow!("Insufficient permissions"))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_password_hash() {
        let password = "test123456";
        let hash = hash_password(password).unwrap();
        assert!(verify_password(password, &hash).unwrap());
        assert!(!verify_password("wrong", &hash).unwrap());
    }

    #[test]
    fn test_jwt_token() {
        let secret = "test_secret";
        let token = generate_token("user123", UserRole::Teacher, secret, 2).unwrap();
        let claims = verify_token(&token, secret).unwrap();
        assert_eq!(claims.sub, "user123");
        assert_eq!(claims.role, UserRole::Teacher);
    }
}
